#include "config.h"

#include <arpa/inet.h>
#include <string.h>
#include <errno.h>

#define DBG_SUBSYS S_LIBINTERFACE

#include "sunrpc_proto.h"
#include "net_global.h"
#include "job_dock.h"
#include "sunrpc_reply.h"
#include "sysy_lib.h"
#include "ynet_net.h"
#include "dbg.h"

#pragma pack(1)

typedef struct {
        uint32_t length;
        uint32_t xid;
        uint32_t msgtype;
        uint32_t replystate;
        auth_head_t veri;
        uint32_t acceptstate;
} sunrpc_reply_t;

#pragma pack()

static int __sunrpc_reply_prep(uint32_t xid, xdr_ret_t xdr_ret,
                               void *_buf, int state, buffer_t *buf)
{
        int ret;
        sunrpc_reply_t *rep;
        xdr_t xdr;

        if (sizeof(sunrpc_reply_t) > PAGE_SIZE) {
                DERROR("why we get such a request? \n");

                YASSERT(0);
        }

        ret = mbuffer_init(buf, sizeof(sunrpc_reply_t));
        if (unlikely(ret))
                GOTO(err_ret, ret);

        rep = mbuffer_head(buf);

        rep->xid = xid;
        rep->msgtype = htonl(SUNRPC_REP_MSG);
        rep->veri.flavor = 0;
        rep->veri.length = 0;
        rep->replystate = 0;
        rep->acceptstate = htonl(state);

        DBUG("state %u\n", rep->acceptstate);
        
        if (_buf && xdr_ret) {
                xdr.op = __XDR_ENCODE;
                xdr.buf = buf;

                if(xdr_ret(&xdr, _buf)) {
                        ret = EINVAL;
                        GOTO(err_ret, ret);
                }
        }

        rep->length = htonl(buf->len - sizeof(uint32_t));
        //rep->length = htonl(buf->len);
        rep->length = htonl(1 << 31) | rep->length;

        DBUG("buf len %llu\n", (LLU)(buf->len - sizeof(uint32_t)));

        return 0;
err_ret:
        return ret;
}

void sunrpc_reply_send(const sockid_t *sockid, uint32_t xid,
                       xdr_ret_t xdr_ret, void *_buf, int state)
{
        int ret;
        buffer_t buf;
        net_handle_t nh;

        ret = __sunrpc_reply_prep(xid, xdr_ret, _buf, state, &buf);
        if (unlikely(ret))
                UNIMPLEMENTED(__DUMP__);

        DBUG("send to %u\n", sockid->sd);
        
        sock2nh(&nh, sockid);
        ret = sdevent_queue(&nh, &buf, 0);
        if (unlikely(ret)) {
                mbuffer_free(&buf);
        }
}
